package sketch.icse11nier;

import gov.nasa.jpf.util.Files;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.SimpleName;

import sketch.ast.ASTFormatter;
import sketch.ast.ASTUtils;
import sketch.main.GeneratingTests;
import sketch.specs.RandomSequenceCreator;
import sketch.specs.RandomSequenceReplaceVisitor;
import sketch.specs.RandomValueVisitor;
import sketch.specs.symbc.SymbolicExecDriverCreator;
import sketch.util.Checker;
import sketch.util.Globals;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class IntegratingOtherTestsTest extends TestCase {

	public static Test suite() {
		return new TestSuite(IntegratingOtherTestsTest.class);
	}
	
	//the test sketch file
	String testSketchFile = "./tests/sketch/icse11nier/Z_Sketch_IntegrateTests.java";
	
	//to output the expanded tests in a specified place
	String outputFileDir = "./tests/sketch/icse11nier/autogenerated/";
	String packageName = "sketch.icse11nier.autogenerated";
	String outputClassName = "TestGeneratedForIntegratingRandom";
	
	public void testIntegratingTests() throws IOException {
		//empty on purpose
		CompilationUnit unit = ASTUtils.astRoot(testSketchFile);
		RandomValueVisitor visitor = new RandomValueVisitor();
		unit.accept(visitor);
		
		Map<MethodInvocation, SimpleName> values = visitor.getRandomValues();
		assertEquals(1, values.size());
		
		Map<MethodInvocation, List<String>> randomSequences = new LinkedHashMap<MethodInvocation, List<String>>();
		
		for(MethodInvocation methodInvoke : values.keySet()) {
			String simpleName = values.get(methodInvoke).getIdentifier();
			List<Class<?>> clazz = RandomValueVisitor.getClasses(methodInvoke);
			Checker.checkTrue(!clazz.isEmpty(), "The clazz list should not be empty, for invocation: " + methodInvoke);
			Class<?> mainClass = clazz.get(0);
			Class<?>[] others = (Class<?>[])clazz.subList(1, clazz.size()).toArray(new Class<?>[0]);
			RandomSequenceCreator sequenceCreator = new RandomSequenceCreator(mainClass, others);
			List<String> seq_txts = sequenceCreator.getSequenceTxtList(simpleName, 1); //1 second
			//System.out.println(seqTxt);
			randomSequences.put(methodInvoke, seq_txts);
		}
		
		Checker.checkTrue(randomSequences.size() == 1, "Assume the size is 1 now.");
		MethodInvocation invoke = null;
		for(MethodInvocation tmp : randomSequences.keySet()) {
			invoke = tmp;
		}
		Checker.checkNull(invoke, "Should not be null.");
		
		int count = 0;
		List<MethodDeclaration> allMethods = new LinkedList<MethodDeclaration>();
		//MethodDeclaration method = ASTUtils.getAllMethods(unit).get(0);
		for(String seq_txt : randomSequences.get(invoke)) {
		  Map<MethodInvocation, String> replace_sequence = new LinkedHashMap<MethodInvocation, String>();
		  replace_sequence.put(invoke, seq_txt);
		  RandomSequenceReplaceVisitor replaceVisitor = new RandomSequenceReplaceVisitor(values, replace_sequence);
		  //CompilationUnit replace_unit = ASTUtils.deepClone(unit);
		  unit.accept(replaceVisitor);
		  
		  String unitstr = replaceVisitor.getResult();
		  
		  CompilationUnit newUnit = ASTUtils.parseUnit(unitstr);
		  
		  List<MethodDeclaration> methods = ASTUtils.getAllMethods(newUnit);
		  for(MethodDeclaration method : methods) {
			  method.getName().setIdentifier(method.getName().toString() + (count++));
			  ASTUtils.makeMethodPublic(method);
			  ASTUtils.addOUnitAnnotation(method);
			  allMethods.add(method);
		  }
		}
		
		//here we get a list of methods
		System.out.println("Get methods: " + allMethods.size());
		
		//output to the dir
		StringBuilder output = new StringBuilder();
		String[] imports = ASTUtils.extractImportDeclarationAsString(unit);
		output.append("package " + this.packageName + ";");
		output.append(Globals.lineSep);
		for(String importStr : imports) {
			output.append(importStr);
			output.append(Globals.lineSep);
		}
		output.append("public class " + this.outputClassName + " extends TestCase {");
		output.append(Globals.lineSep);
		
		for(MethodDeclaration method : allMethods) {
			output.append(method.toString());
			output.append(Globals.lineSep);
		}
		
		output.append("}");
		output.append(Globals.lineSep);
		
		String outputFP =  outputFileDir + Globals.fileSep +  this.outputClassName + ".java";
		Files.writeToFile(output.toString(),outputFP);
		
		CompilationUnit newUnit = ASTUtils.astRoot(outputFP);
		String[] extraImports = new String[]{"sketch.ounit.Observer", "sketch.ounit.Values",
				"sketch.specs.annotation.TestSketch", "treemap.TreeMap", "junit.framework.TestCase",
				packageName + "." + outputClassName + SymbolicExecDriverCreator.SYMBOLIC};
		GeneratingTests.genSymbolicValuesToOutputTests(newUnit, outputFileDir, outputClassName, packageName, extraImports,
				treemap.TreeMap.class, "remove");
	}
}
